import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Upload, message } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import type { UploadFile, UploadProps } from 'antd/es/upload/interface';
import { RcFile } from "antd/lib/upload";
import {
  completeImgUrl,
  getAllExtByLowerCase,
  getFileExtByName,
  getFilenameByKey,
  ossDomain
} from "common/utils/utils";
import {FileGroup} from "common/utils/data";
import dayjs from "dayjs";
import axios from "axios";
import {fileV1AdminControllerCreateUploadToken} from '@/services/auto/fileAdmin';

interface FileListItem {
  url?: string; // 绝对url地址，带http开头的
  uid: string; // antd随机值 或 相对url地址，对应Value中的Url
  name: string; // 文件原始名称
  status: UploadFile['status']; // 上传状态
  percent?: number; // 进度条
}

interface Props {
  value?: string[];
  max?: number;
  onChange?: (value?: string[]) => void;
  fileGroup: FileGroup;
  id?: string;
  ext?: string[];
  itemRender?: UploadProps['itemRender'];
  size?: number;
  disabled?: boolean;
}

const DEFAULT_VALUE: string[] = [];
const DEFAULT_EXT = ['.jpg', '.jpeg', '.png', '.gif'];
const DEFAULT_SIZE = 5;

// 给Form.Item添加value和onChange接口
export default function FileUpload(props: Props) {
  const {
    max = 1,
    size = DEFAULT_SIZE,
    value = DEFAULT_VALUE,
    onChange,
    fileGroup,
    id,
    itemRender,
    ext = DEFAULT_EXT,
    disabled,
  } = props;

  const [fileList, setFileList] = useState<FileListItem[]>([]);

  // 通过tempValue来触发onChange tempValue可以队列设置改变，直接调用onChange会丢失数据
  const [tempValue, setTempValue] = useState<string[]>(value);

  const hackAntdBugRecordUidUrlMap = useRef<Record<string, string>>({});

  const onChanging = useRef<boolean>(false);

  const allExt = useMemo(()=>{
    return getAllExtByLowerCase(ext);
  },[ext])

  useEffect(() => {
    if (!onChanging.current) {
      setFileList(
        value.map((item) => {
          return {
            url: completeImgUrl(item),
            uid: item,
            name: getFilenameByKey(item),
            status: 'done',
          };
        }),
      );
      setTempValue(value);
    }
    onChanging.current = false;
  }, [value.join(',')]);

  const onChangeValue = (val: string[]) => {
    onChanging.current = true;
    onChange?.(val);
  };

  useEffect(() => {
    if (tempValue.join(',') !== value.join(',')) {
      onChangeValue(tempValue);
    }
  }, [tempValue]);

  // 上传前判断
  const beforeUpload = useCallback(
    (file: RcFile, fileListParam: RcFile[]) => {
      if (fileListParam.length > max - fileList.length) {
        message.warning('超过最大上传数');
        return false;
      }
      if (!allExt.some((item) => file.name.endsWith(item))) {
        message.warning(`只可以上传 ${allExt.join('，')} 格式的文件!`);
        return false;
      }
      if (!(file.size / 1024 / 1024 < size)) {
        message.warning(`大小须小于${size}M!`);
        return false;
      }
      return true;
    },
    [fileList, max, allExt],
  );

  return (
    <Upload
      id={id}
      disabled={disabled}
      itemRender={itemRender}
      customRequest={(options) => {
        const { onProgress, onSuccess, onError } = options;
        const file = options.file as RcFile;

        onProgress?.({ percent: 0 });
        fileV1AdminControllerCreateUploadToken({
          filename: file.name,
          group: fileGroup,
        }).then((res)=>{
          const formData = new FormData();
          formData.append('OSSAccessKeyId', res.OSSAccessKeyId);
          formData.append('policy', res.policy);
          formData.append('Signature', res.Signature);
          formData.append('key', res.key);
          formData.append('file', file);

          return axios.request({
            url: ossDomain,
            data: formData,
            method: 'POST',
            onUploadProgress: (e)=>{
              onProgress?.({ percent: e.progress });
            }
          }).then(()=>{
            onSuccess?.({ key: res.key });
          })
        }).catch((err)=>{
          onError?.(err, err?.message)
        })

      }}
      accept={allExt.join(',')}
      listType="picture-card"
      multiple
      beforeUpload={beforeUpload}
      fileList={fileList as any}
      onChange={(info) => {
        const file = info.file;
        if (file.status === 'done') {
          setTempValue((origin) => {
            return origin.concat([file.response.key]);
          });
        }
        setFileList(
          info.fileList
            .filter((item) => !!item.status)
            .map((item) => {
              const newItem: FileListItem = {
                url: item.url,
                uid: item.uid,
                name: item.name,
                percent: item.percent,
                status: item.status,
              };
              if (!!item.response?.key && !item.url) {
                // 本次新上传的文件
                // antd upload组件会有莫名其妙的乱对应关系，所以只能拿一个对象来记录名字与url
                if (!hackAntdBugRecordUidUrlMap.current[item.uid]) {
                  const url = completeImgUrl(file.response.key);
                  newItem.url = url;
                  hackAntdBugRecordUidUrlMap.current[item.uid] = url;
                } else {
                  newItem.url = hackAntdBugRecordUidUrlMap.current[item.uid];
                }
                // 这里没有强行修改uid为item.response.url的原因是uid改变，Upload组件会闪一下，就不改了，删除的时候用绝对地址去判断索引
              }
              return newItem;
            }),
        );
      }}
      onRemove={(file) => {
        const newValue = [...value];
        const index = newValue.findIndex((item) => completeImgUrl(item) === file.url);
        if (index > -1) {
          // 这里有可能是删除上传失败的文件，要判断index
          setTempValue((origin) => {
            const newOrigin = [...origin];
            newOrigin.splice(index, 1);
            return newOrigin;
          });
        }
      }}
    >
      {(fileList.length < max && !disabled) && (
        <div>
          <PlusOutlined />
          <div>上传文件</div>
        </div>
      )}
    </Upload>
  );
}
